home *** CD-ROM | disk | FTP | other *** search
/ Micromanía 92 / CDMM92_1.ISO / SOF 2 SDK / sof2sdk-101.msi / _92D6AC311BB48EBA344BBABC89DA6AB0 / _7D4AF05E7D9D49AA95FD45DD06FE2ADF < prev    next >
Encoding:
Text File  |  2002-06-24  |  25.0 KB  |  1,055 lines

  1. // Copyright (C) 2001-2002 Raven Software
  2. //
  3. #include "g_local.h"
  4.  
  5. /*
  6.  
  7.   Items are any object that a player can touch to gain some effect.
  8.  
  9.   Pickup will return the number of seconds until they should respawn.
  10.  
  11.   all items should pop when dropped in lava or slime
  12.  
  13.   Respawnable items don't actually go away when picked up, they are
  14.   just made invisible and untouchable.  This allows them to ride
  15.   movers and respawn apropriately.
  16. */
  17.  
  18.  
  19. #define    RESPAWN_ARMOR        25
  20. #define    RESPAWN_HEALTH        35
  21. #define    RESPAWN_AMMO        40
  22. #define RESPAWN_BACKPACK    40
  23.  
  24. extern gentity_t *droppedRedFlag;
  25. extern gentity_t *droppedBlueFlag;
  26.  
  27. //======================================================================
  28. void Add_Ammo (gentity_t *ent, int ammoindex, int count)
  29. {
  30.     ent->client->ps.ammo[ammoindex] += count;
  31.     
  32.     if ( ent->client->ps.ammo[ammoindex] > ammoData[ammoindex].max ) 
  33.     {
  34.         ent->client->ps.ammo[ammoindex] = ammoData[ammoindex].max;
  35.     }
  36. }
  37.  
  38. int Pickup_Ammo (gentity_t *ent, gentity_t *other)
  39. {
  40.     int    quantity;
  41.  
  42.     if ( ent->count ) 
  43.     {
  44.         quantity = ent->count;
  45.     } 
  46.     else 
  47.     {
  48.         quantity = ent->item->quantity;
  49.     }
  50.  
  51.     Add_Ammo (other, ent->item->giTag, quantity);
  52.  
  53.     return RESPAWN_AMMO;
  54. }
  55.  
  56. //======================================================================
  57.  
  58.  
  59. int Pickup_Weapon (gentity_t *ent, gentity_t *other, qboolean* autoswitch ) 
  60. {
  61.     int            quantity;
  62.     int            weaponNum = ent->item->giTag;
  63.     qboolean    hasAltAmmo;
  64.  
  65.     hasAltAmmo = BG_WeaponHasAlternateAmmo ( weaponNum );
  66.  
  67.     if ( ent->count < 0 ) 
  68.     {
  69.         quantity = 0; // None for you, sir!
  70.     } 
  71.     else 
  72.     {        
  73.         if ( ent->count ) 
  74.         {
  75.             quantity = ent->count;
  76.         } 
  77.         else 
  78.         {
  79.             quantity = weaponData[weaponNum].attack[ATTACK_NORMAL].clipSize + (weaponData[weaponNum].attack[ATTACK_ALTERNATE].clipSize<<16);
  80.         }
  81.     }
  82.  
  83.     // Add the ammo in, dont use Add_Ammo because we may temporarily pass the max
  84.     // ammo here and add_ammo wont let us do that.
  85.     other->client->ps.ammo[weaponData[weaponNum].attack[ATTACK_NORMAL].ammoIndex] += (quantity&0xFF);
  86.     other->client->ps.ammo[weaponData[weaponNum].attack[ATTACK_NORMAL].ammoIndex] += ((quantity>>8)&0xFF);
  87.  
  88.     if ( hasAltAmmo )
  89.     {
  90.         other->client->ps.ammo[weaponData[weaponNum].attack[ATTACK_ALTERNATE].ammoIndex] += ((quantity>>16)&0xFF);
  91.         other->client->ps.ammo[weaponData[weaponNum].attack[ATTACK_ALTERNATE].ammoIndex] += ((quantity>>24)&0xFF);
  92.     }
  93.  
  94.     // If just picked up move some ammo into the clip
  95.     if ( !(other->client->ps.stats[STAT_WEAPONS]&(1<<weaponNum)) )
  96.     {
  97.         // Copy over the clips
  98.         other->client->ps.clip[ATTACK_NORMAL][weaponNum] = (quantity&0xFF);
  99.         other->client->ps.ammo[weaponData[weaponNum].attack[ATTACK_NORMAL].ammoIndex] -= other->client->ps.clip[ATTACK_NORMAL][weaponNum];
  100.  
  101.         if ( hasAltAmmo )
  102.         {
  103.             other->client->ps.clip[ATTACK_ALTERNATE][weaponNum] = ((quantity>>16)&0xFF);
  104.             other->client->ps.ammo[weaponData[weaponNum].attack[ATTACK_ALTERNATE].ammoIndex] -= other->client->ps.clip[ATTACK_ALTERNATE][weaponNum];
  105.         }
  106.         
  107.         if ( other->client->ps.weaponstate != WEAPON_CHARGING      &&
  108.              other->client->ps.weaponstate != WEAPON_CHARGING_ALT    )
  109.         {
  110.             // Autoswitch the weapon
  111.             *autoswitch = qtrue;
  112.         }
  113.  
  114.         other->client->ps.firemode[weaponNum] = BG_FindFireMode ( weaponNum, ATTACK_NORMAL, WP_FIREMODE_AUTO );
  115.     }
  116.  
  117.     // Call add ammo with 0 ammo to force it to cap it at max
  118.     Add_Ammo( other, weaponData[weaponNum].attack[ATTACK_NORMAL].ammoIndex, 0 );
  119.  
  120.     if ( hasAltAmmo )
  121.     {
  122.         Add_Ammo( other, weaponData[weaponNum].attack[ATTACK_ALTERNATE].ammoIndex, 0 );
  123.     }
  124.  
  125.     // add the weapon
  126.     other->client->ps.stats[STAT_WEAPONS] |= ( 1 << weaponNum );
  127.  
  128.     return g_weaponRespawn.integer;
  129. }
  130.  
  131.  
  132. //======================================================================
  133.  
  134. int Pickup_Health (gentity_t *ent, gentity_t *other) 
  135. {
  136.     int            quantity;
  137.  
  138.     if ( ent->count ) 
  139.     {
  140.         quantity = ent->count;
  141.     } 
  142.     else 
  143.     {
  144.         quantity = ent->item->quantity;
  145.     }
  146.  
  147.     other->health += quantity;
  148.  
  149.     if (other->health > MAX_HEALTH ) 
  150.     {
  151.         other->health = MAX_HEALTH;
  152.     }
  153.  
  154.     other->client->ps.stats[STAT_HEALTH] = other->health;
  155.  
  156.     return RESPAWN_HEALTH;
  157. }
  158.  
  159. //======================================================================
  160.  
  161. int Pickup_Armor( gentity_t *ent, gentity_t *other ) 
  162. {
  163.     other->client->ps.stats[STAT_ARMOR] += ent->item->quantity;
  164.  
  165.     if ( other->client->ps.stats[STAT_ARMOR] > MAX_ARMOR ) 
  166.     {
  167.         other->client->ps.stats[STAT_ARMOR] = MAX_ARMOR;
  168.     }
  169.  
  170.     return RESPAWN_ARMOR;
  171. }
  172.  
  173. //======================================================================
  174.  
  175. int Pickup_Gametype (gentity_t *ent, gentity_t *other) 
  176. {
  177.     other->client->ps.stats[STAT_GAMETYPE_ITEMS] |= (1<<ent->item->giTag);
  178.  
  179.     return -1;
  180. }
  181.  
  182. int Pickup_Backpack ( gentity_t* ent, gentity_t* other )
  183. {
  184.     float            percent = (float)ent->item->quantity / 100.0f;
  185.     int                i;
  186.     playerState_t    *ps;
  187.  
  188.     ps = &other->client->ps;
  189.  
  190.     // Fill up their health
  191.     ps->stats[STAT_HEALTH] += MAX_HEALTH * percent;
  192.     if ( ps->stats[STAT_HEALTH] > MAX_HEALTH )
  193.     {
  194.         ps->stats[STAT_HEALTH] = MAX_HEALTH;
  195.     }
  196.     other->health = ps->stats[STAT_HEALTH];
  197.  
  198.     // Cant get armor when you have goggles
  199.     if ( !ps->stats[STAT_GOGGLES] )
  200.     {
  201.         ps->stats[STAT_ARMOR] += MAX_HEALTH * percent;
  202.         if ( ps->stats[STAT_ARMOR] > MAX_ARMOR )
  203.         {
  204.             ps->stats[STAT_ARMOR] = MAX_ARMOR;
  205.         }
  206.     }
  207.  
  208.     // Give them some ammo
  209.     for ( i = 0; i < MAX_AMMO; i ++ )
  210.     {
  211.         int    maxammo;
  212.  
  213.         maxammo = BG_GetMaxAmmo ( ps, i);
  214.  
  215.         if ( !maxammo || ps->ammo[i] >= maxammo )
  216.         {
  217.             continue;
  218.         }
  219.  
  220.         ps->ammo[i] += Com_Clamp ( 1, maxammo, maxammo * percent );
  221.         if ( ps->ammo[i] >= maxammo )
  222.         {
  223.             ps->ammo[i] = maxammo;
  224.         }
  225.     }
  226.  
  227.     // Make sure you alwasy get grenades
  228.     if ( level.pickupsDisabled )
  229.     {
  230.         weapon_t weapon = ps->stats[STAT_OUTFIT_GRENADE];
  231.  
  232.         // If the client doesnt even have a greande then we need to give them one
  233.         // and fill their clip.  They should have already been give ammo 
  234.         if ( !(ps->stats[STAT_WEAPONS] & (1<<weapon)) )
  235.         {
  236.             int ammoIndex;
  237.  
  238.             ps->stats[STAT_WEAPONS] |= (1<<weapon);
  239.  
  240.             // Move over the ammo to a clip
  241.             ammoIndex = weaponData[weapon].attack[ATTACK_NORMAL].ammoIndex;
  242.             ps->ammo[ammoIndex] -= weaponData[weapon].attack[ATTACK_NORMAL].clipSize;
  243.             ps->clip[ATTACK_NORMAL][weapon] = weaponData[weapon].attack[ATTACK_NORMAL].clipSize;
  244.         }
  245.     }
  246.  
  247.     return g_backpackRespawn.integer;
  248. }
  249.  
  250. /*
  251. ===============
  252. RespawnItem
  253. ===============
  254. */
  255. void RespawnItem( gentity_t *ent ) 
  256. {
  257.     // randomly select from teamed entities
  258.     if (ent->team) 
  259.     {
  260.         gentity_t    *master;
  261.         int    count;
  262.         int choice;
  263.  
  264.         if ( !ent->teammaster ) 
  265.         {
  266.             Com_Error( ERR_FATAL, "RespawnItem: bad teammaster");
  267.         }
  268.         master = ent->teammaster;
  269.  
  270.         for (count = 0, ent = master; ent; ent = ent->teamchain, count++)
  271.             ;
  272.  
  273.         choice = rand() % count;
  274.  
  275.         for (count = 0, ent = master; count < choice; ent = ent->teamchain, count++)
  276.             ;
  277.     }
  278.  
  279.     ent->r.contents = CONTENTS_TRIGGER;
  280.     ent->s.eFlags &= ~EF_NODRAW;
  281.     ent->r.svFlags &= ~SVF_NOCLIENT;
  282.     trap_LinkEntity (ent);
  283.  
  284.     // play the normal respawn sound only to nearby clients
  285.     G_AddEvent( ent, EV_ITEM_RESPAWN, 0 );
  286.  
  287.     ent->nextthink = 0;
  288. }
  289.  
  290.  
  291. /*
  292. ===============
  293. Touch_Item
  294. ===============
  295. */
  296. void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) 
  297. {
  298.     int            respawn;
  299.     qboolean    predict;
  300.     qboolean    autoswitch;
  301.  
  302.     if (!other->client)
  303.         return;
  304.  
  305.     // dead people can't pickup
  306.     if (other->health < 1)
  307.         return;        
  308.  
  309.     // See if teh item can be picked up
  310.     if( ent->s.eFlags & EF_NOPICKUP )
  311.     {
  312.         return;
  313.     }
  314.  
  315.     // If its a gametype item the gametype handles it
  316.     if ( ent->item->giType == IT_GAMETYPE )
  317.     {
  318.         // Let the gametype decide if it can be picked up
  319.         if ( !trap_GT_SendEvent ( GTEV_ITEM_TOUCHED, level.time, level.gametypeItems[ent->item->giTag].id, other->s.number, other->client->sess.team, 0, 0 ) )
  320.         {
  321.             return;
  322.         }
  323.     }
  324.     // the same pickup rules are used for client side and server side
  325.     else if ( !BG_CanItemBeGrabbed( level.gametype, &ent->s, &other->client->ps ) ) 
  326.     {
  327.         return;
  328.     }
  329.  
  330. #ifdef _DEBUG
  331.     G_LogPrintf( "Item: %i %s\n", other->s.number, ent->item->classname );
  332. #endif
  333.  
  334.     // Initialize booleans
  335.     predict    = other->client->pers.predictItemPickup;
  336.     autoswitch = qfalse;
  337.  
  338.     // call the item-specific pickup function
  339.     switch( ent->item->giType ) 
  340.     {
  341.         case IT_WEAPON:
  342.             respawn = Pickup_Weapon(ent, other, &autoswitch );
  343.             break;
  344.         case IT_AMMO:
  345.             respawn = Pickup_Ammo(ent, other);
  346.             break;
  347.         case IT_ARMOR:
  348.             respawn = Pickup_Armor(ent, other);
  349.             break;
  350.         case IT_HEALTH:
  351.             respawn = Pickup_Health(ent, other);
  352.             break;
  353.         case IT_GAMETYPE:
  354.             respawn = Pickup_Gametype(ent, other);
  355.             predict = qfalse;
  356.             break;
  357.         case IT_BACKPACK:
  358.             respawn = Pickup_Backpack(ent,other);
  359.             predict = qfalse;
  360.             break;
  361.         default:
  362.             return;
  363.     }
  364.  
  365.     if ( !respawn ) 
  366.     {
  367.         return;
  368.     }
  369.  
  370.     // play the normal pickup sound
  371.     if (predict) 
  372.     {
  373.         G_AddPredictableEvent( other, EV_ITEM_PICKUP, ent->s.modelindex | (autoswitch?ITEM_AUTOSWITCHBIT:0) );
  374.     } 
  375.     else 
  376.     {
  377.         G_AddEvent( other, EV_ITEM_PICKUP, ent->s.modelindex | (autoswitch?ITEM_AUTOSWITCHBIT:0) );
  378.     }
  379.  
  380.     // fire item targets
  381.     G_UseTargets (ent, other);
  382.  
  383.     // wait of -1 will not respawn
  384.     if ( ent->wait == -1 ) 
  385.     {
  386.         ent->r.svFlags |= SVF_NOCLIENT;
  387.         ent->s.eFlags |= EF_NODRAW;
  388.         ent->r.contents = 0;
  389.         ent->unlinkAfterEvent = qtrue;
  390.         return;
  391.     }
  392.  
  393.     // non zero wait overrides respawn time
  394.     if ( ent->wait ) 
  395.     {
  396.         respawn = ent->wait;
  397.     }
  398.  
  399.     // random can be used to vary the respawn time
  400.     if ( ent->random ) 
  401.     {
  402.         respawn += crandom() * ent->random;
  403.         
  404.         if ( respawn < 1 ) 
  405.         {
  406.             respawn = 1;
  407.         }
  408.     }
  409.  
  410.     // dropped items will not respawn
  411.     if ( ent->flags & FL_DROPPED_ITEM ) 
  412.     {
  413.         ent->freeAfterEvent = qtrue;
  414.     }
  415.  
  416.     // picked up items still stay around, they just don't
  417.     // draw anything.  This allows respawnable items
  418.     // to be placed on movers.
  419.     ent->r.svFlags |= SVF_NOCLIENT;
  420.     ent->s.eFlags |= EF_NODRAW;
  421.     ent->r.contents = 0;
  422.  
  423.     // ZOID
  424.     // A negative respawn times means to never respawn this item (but don't 
  425.     // delete it).  This is used by items that are respawned by third party events
  426.     if ( respawn <= 0 ) 
  427.     {
  428.         ent->nextthink = 0;
  429.         ent->think = 0;
  430.     } 
  431.     else 
  432.     {
  433.         ent->nextthink = level.time + respawn * 1000;
  434.         ent->think = RespawnItem;
  435.     }
  436.  
  437.     trap_LinkEntity( ent );
  438. }
  439.  
  440.  
  441. //======================================================================
  442.  
  443. /*
  444. ================
  445. LaunchItem
  446.  
  447. Spawns an item and tosses it forward
  448. ================
  449. */
  450. gentity_t *LaunchItem( gitem_t *item, vec3_t origin, vec3_t velocity ) 
  451. {
  452.     gentity_t    *dropped;
  453.  
  454.     // Gametype items must be spawned using the spawn mission item function
  455.     if ( item->giType == IT_GAMETYPE )
  456.     {
  457.         dropped = G_SpawnGametypeItem ( item->pickup_name, qtrue, origin );
  458.         dropped->nextthink = 0;
  459.     }
  460.     else
  461.     {
  462.         dropped = G_Spawn();
  463.         dropped->think = G_FreeEntity;
  464.         dropped->nextthink = level.time + 30000;
  465.     }
  466.  
  467.     if ( !dropped )
  468.     {
  469.         return NULL;
  470.     }
  471.  
  472.     dropped->s.eType = ET_ITEM;
  473.     dropped->s.modelindex = item - bg_itemlist;    // store item number in modelindex
  474.     dropped->s.modelindex2 = 1; // This is non-zero is it's a dropped item
  475.  
  476.     dropped->classname = item->classname;
  477.     dropped->item = item;
  478.     VectorSet (dropped->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS);
  479.     VectorSet (dropped->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS);
  480.     dropped->r.contents = CONTENTS_TRIGGER;
  481.  
  482.     dropped->touch = Touch_Item;
  483.  
  484.     G_SetOrigin( dropped, origin );
  485.     dropped->s.pos.trType = TR_GRAVITY;
  486.     dropped->s.pos.trTime = level.time;
  487.     VectorCopy( velocity, dropped->s.pos.trDelta );
  488.  
  489.     dropped->s.eFlags |= EF_BOUNCE_HALF;
  490.  
  491.     dropped->flags = FL_DROPPED_ITEM;
  492.  
  493.     trap_LinkEntity (dropped);
  494.  
  495.     return dropped;
  496. }
  497.  
  498. /*
  499. ================
  500. G_DropItem
  501.  
  502. Spawns an item and tosses it forward
  503. ================
  504. */
  505. gentity_t *G_DropItem( gentity_t *ent, gitem_t *item, float angle ) 
  506. {
  507.     vec3_t        velocity;
  508.     vec3_t        angles;
  509.     gentity_t*    dropped;
  510.  
  511.     VectorCopy( ent->s.apos.trBase, angles );
  512.     angles[YAW] += angle;
  513.     angles[PITCH] = 0;    // always forward
  514.  
  515.     AngleVectors( angles, velocity, NULL, NULL );
  516.     VectorScale( velocity, 100, velocity );
  517.     velocity[2] += 100 + crandom() * 50;
  518.     
  519.     dropped = LaunchItem( item, ent->r.currentOrigin, velocity );
  520.  
  521.     if ( item->giType == IT_GAMETYPE )
  522.     {
  523.         trap_GT_SendEvent ( GTEV_ITEM_DROPPED, level.time, level.gametypeItems[item->giTag].id, ent->s.number, 0, 0, 0 );
  524.     }
  525.  
  526.     return dropped;
  527. }
  528.  
  529. /*
  530. =================
  531. G_EnablePickup
  532.  
  533. Re-enables pickup on a entity that has it disabled
  534. =================
  535. */
  536. void G_EnablePickup ( gentity_t* ent )
  537. {
  538.     ent->s.eFlags &= ~EF_NOPICKUP;
  539.  
  540.     // If this is a no respawn game we can keep the weapons around till round end
  541.     if ( level.gametypeData->respawnType == RT_NONE )
  542.     {
  543.         return;
  544.     }
  545.  
  546.     // Go away in 30 seconds
  547.     ent->think = G_FreeEntity;
  548.     ent->nextthink = level.time + 30000;
  549. }
  550.  
  551. /*
  552. =================
  553. G_IsAmmoBeingShared
  554.  
  555. determins if the given ammo index is being shared by any other weapon in the players
  556. inventory.  Excluding the specified weapon
  557. =================
  558. */
  559. qboolean G_IsAmmoBeingShared ( gentity_t* ent, int ammoIndex, weapon_t exclude )
  560. {
  561.     weapon_t weapon;
  562.  
  563.     // Need to figure out if this guy has any other guns that use the ammo for the gun
  564.     // being dropped.
  565.     for ( weapon = WP_KNIFE + 1; weapon < WP_NUM_WEAPONS; weapon ++ )
  566.     {
  567.         // Does the player have this weapon?
  568.         if ( !(ent->client->ps.stats[STAT_WEAPONS] & (1<<weapon) ) )
  569.         {
  570.             continue;
  571.         }
  572.  
  573.         // Dont include the weapon being dropped
  574.         if ( exclude == weapon )
  575.         {
  576.             continue;
  577.         }
  578.  
  579.         // Does this attack use the specified ammo?
  580.         if ( weaponData[weapon].attack[ATTACK_NORMAL].ammoIndex == ammoIndex )
  581.         {
  582.             return qtrue;
  583.         }
  584.  
  585.         // Does this attack use the specified ammo?
  586.         if ( weaponData[weapon].attack[ATTACK_ALTERNATE].ammoIndex == ammoIndex )
  587.         {
  588.             return qtrue;
  589.         }
  590.     }
  591.  
  592.     return qfalse;
  593. }
  594.  
  595. /*
  596. =================
  597. G_DropWeapon
  598.  
  599. Drops the weapon and all its ammo
  600. =================
  601. */
  602. gentity_t* G_DropWeapon ( gentity_t* ent, weapon_t weapon, int pickupDelay )
  603. {
  604.     gentity_t*    dropped;
  605.     gitem_t*    item;
  606.     vec3_t        angles;
  607.     
  608.     if ( weapon <= WP_KNIFE || weapon >= WP_NUM_WEAPONS )
  609.     {
  610.         return NULL;
  611.     }
  612.  
  613.     // No more outfitting changes
  614.     ent->client->noOutfittingChange = qtrue;
  615.  
  616.     // find the item type for this weapon
  617.     item = BG_FindWeaponItem ( weapon );
  618.  
  619.     // spawn the item
  620.     dropped = G_DropItem( ent, item, 0 );
  621.  
  622.     // Pack all the ammo into the count field
  623.     dropped->s.angles[YAW] = rand()%360;
  624.     dropped->count  = (ent->client->ps.clip[ATTACK_NORMAL][weapon]&0xFF);
  625.  
  626.     // If the ammo isnt being shared then send it all with the gun
  627.     if ( !G_IsAmmoBeingShared ( ent, weaponData[weapon].attack[ATTACK_NORMAL].ammoIndex, weapon ) )
  628.     {
  629.         dropped->count += ((ent->client->ps.ammo[weaponData[weapon].attack[ATTACK_NORMAL].ammoIndex]<<8) & 0xFF00);
  630.         ent->client->ps.ammo[weaponData[weapon].attack[ATTACK_NORMAL].ammoIndex] = 0;
  631.     }
  632.  
  633.     // Dont bother if the weapon doesnt have alternate ammo
  634.     if ( BG_WeaponHasAlternateAmmo ( weapon ) )
  635.     {
  636.         dropped->count += ((ent->client->ps.clip[ATTACK_ALTERNATE][weapon] << 16) & 0xFF0000 );    
  637.  
  638.         // If the ammo isnt being shared then send it all with the gun
  639.         if ( !G_IsAmmoBeingShared ( ent, weaponData[weapon].attack[ATTACK_ALTERNATE].ammoIndex, weapon ) )
  640.         {
  641.             dropped->count += ((ent->client->ps.ammo[weaponData[weapon].attack[ATTACK_ALTERNATE].ammoIndex] << 24) & 0xFF000000 );
  642.             ent->client->ps.ammo[weaponData[weapon].attack[ATTACK_ALTERNATE].ammoIndex] = 0;
  643.         }
  644.     }
  645.  
  646.     // Clear the clips
  647.     ent->client->ps.clip[ATTACK_NORMAL][weapon] = 0;
  648.     ent->client->ps.clip[ATTACK_ALTERNATE][weapon] = 0;    
  649.  
  650.     // Take the weapon away
  651.     ent->client->ps.stats[STAT_WEAPONS] &= ~(1<<weapon);
  652.  
  653.     // if the gun is empty then just kill it soon after its dropped
  654.     if ( !dropped->count )
  655.     {
  656.         dropped->nextthink = level.time + 2500;
  657.         dropped->think     = G_FreeEntity;
  658.         dropped->s.eFlags |= EF_NOPICKUP;
  659.     }
  660.     // Dont allow the item to be picked up againt for 3 seconds if in a no pickup game, otherwise
  661.     // let them pick it up immediately
  662.     else if ( pickupDelay )
  663.     {
  664.         dropped->nextthink = level.time + 3000;    
  665.         dropped->s.eFlags |= EF_NOPICKUP;
  666.         dropped->think = G_EnablePickup;
  667.     }
  668.     // Always need a tad bit of delay on pickup for prediction issues
  669.     else
  670.     {
  671.         dropped->nextthink = level.time + 200;    
  672.         dropped->s.eFlags |= EF_NOPICKUP;
  673.         dropped->think = G_EnablePickup;
  674.     }
  675.  
  676.     // Throw the gun forward
  677.     VectorCopy( ent->s.apos.trBase, angles );
  678.     angles[PITCH] = 0;
  679.  
  680.     // Some random velocity
  681.     AngleVectors( angles, ent->s.pos.trDelta, NULL, NULL );
  682.     VectorScale( ent->s.pos.trDelta, 150, ent->s.pos.trDelta );
  683.     ent->s.pos.trDelta[2] += 200 + random() * 50;
  684.  
  685.     return dropped;
  686. }
  687.  
  688. /*
  689. ================
  690. Use_Item
  691.  
  692. Respawn the item
  693. ================
  694. */
  695. void Use_Item( gentity_t *ent, gentity_t *other, gentity_t *activator ) 
  696. {
  697.     RespawnItem( ent );
  698. }
  699.  
  700. //======================================================================
  701.  
  702. /*
  703. ================
  704. FinishSpawningItem
  705.  
  706. Traces down to find where an item should rest, instead of letting them
  707. free fall from their spawn points
  708. ================
  709. */
  710. void FinishSpawningItem( gentity_t *ent ) 
  711. {
  712.     trace_t        tr;
  713.     vec3_t        dest;
  714.     vec3_t        src;
  715. //    gitem_t        *item;
  716.  
  717.     VectorSet( ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS );
  718.     VectorSet( ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS );
  719.  
  720.     ent->s.eType = ET_ITEM;
  721.     ent->s.modelindex = ent->item - bg_itemlist;        // store item number in modelindex
  722.     ent->s.modelindex2 = 0; // zero indicates this isn't a dropped item
  723.  
  724.     ent->r.contents = CONTENTS_TRIGGER;
  725.     ent->touch = Touch_Item;
  726.     // useing an item causes it to respawn
  727.     ent->use = Use_Item;
  728.  
  729.     // create a Ghoul2 model if the world model is a glm
  730. /*    item = &bg_itemlist[ ent->s.modelindex ];
  731.     if (!stricmp(&item->world_model[0][strlen(item->world_model[0]) - 4], ".glm"))
  732.     {
  733.         trap_G2API_InitGhoul2Model(&ent->s, item->world_model[0], G_ModelIndex(item->world_model[0] ), 0, 0, 0, 0);
  734.         ent->s.radius = 60;
  735.     }
  736. */
  737.     if ( ent->item->giType != IT_GAMETYPE && (ent->spawnflags & 1) ) 
  738.     {
  739.         // suspended
  740.         G_SetOrigin( ent, ent->s.origin );
  741.     } 
  742.     else 
  743.     {        
  744.         // drop to floor
  745.         VectorSet( src, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] + 1 );
  746.         VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 );
  747.         trap_Trace( &tr, src, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID );
  748.         if ( tr.startsolid ) 
  749.         {
  750.             Com_Printf ("FinishSpawningItem: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin));
  751.             G_FreeEntity( ent );
  752.             return;
  753.         }
  754.  
  755.         // allow to ride movers
  756.         ent->s.groundEntityNum = tr.entityNum;
  757.  
  758.         G_SetOrigin( ent, tr.endpos );
  759.     }
  760.  
  761.     // team slaves and targeted items aren't present at start
  762.     if ( ( ent->flags & FL_TEAMSLAVE ) || ent->targetname ) {
  763.         ent->s.eFlags |= EF_NODRAW;
  764.         ent->r.contents = 0;
  765.         return;
  766.     }
  767.  
  768.     // Gametype items are broadcast
  769.     if ( ent->item->giType == IT_GAMETYPE )
  770.     {
  771.         ent->r.svFlags |= SVF_BROADCAST;
  772.     }
  773.  
  774.     trap_LinkEntity (ent);
  775. }
  776.  
  777.  
  778. qboolean    itemRegistered[MAX_ITEMS];
  779.  
  780. /*
  781. ==============
  782. ClearRegisteredItems
  783. ==============
  784. */
  785. void ClearRegisteredItems( void ) 
  786. {
  787.     memset( itemRegistered, 0, sizeof( itemRegistered ) );
  788.  
  789.     // players always start with the base weapon
  790.     RegisterItem( BG_FindWeaponItem ( WP_FIRST_RANGED_WEAPON ) );
  791.     RegisterItem( BG_FindWeaponItem ( WP_KNIFE ) );
  792. }
  793.  
  794. /*
  795. ===============
  796. RegisterItem
  797.  
  798. The item will be added to the precache list
  799. ===============
  800. */
  801. void RegisterItem( gitem_t *item ) 
  802. {
  803.     if ( !item ) 
  804.     {
  805.         Com_Printf( "RegisterItem: NULL" );
  806.     }
  807.  
  808.     itemRegistered[ item - bg_itemlist ] = qtrue;
  809. }
  810.  
  811. /*
  812. ===============
  813. SaveRegisteredItems
  814.  
  815. Write the needed items to a config string
  816. so the client will know which ones to precache
  817. ===============
  818. */
  819. void SaveRegisteredItems( void ) 
  820. {
  821.     char    string[MAX_ITEMS+1];
  822.     int        i;
  823.     int        count;
  824.  
  825.     count = 0;
  826.     for ( i = 0 ; i < bg_numItems ; i++ ) 
  827.     {
  828.         if ( itemRegistered[i] ) 
  829.         {
  830.             count++;
  831.             string[i] = '1';
  832.         }
  833.         else 
  834.         {
  835.             string[i] = '0';
  836.         }
  837.     }
  838.     
  839.     string[ bg_numItems ] = 0;
  840.  
  841.     Com_Printf( "%i items registered\n", count );
  842.     trap_SetConfigstring(CS_ITEMS, string);
  843. }
  844.  
  845. /*
  846. ============
  847. G_ItemDisabled
  848. ============
  849. */
  850. int G_ItemDisabled( gitem_t *item ) 
  851. {
  852.     char name[128];
  853.     Com_sprintf(name, sizeof(name), "disable_%s", item->classname);
  854.     return trap_Cvar_VariableIntegerValue( name );
  855. }
  856.  
  857. /*
  858. ============
  859. G_SpawnItem
  860.  
  861. Sets the clipping size and plants the object on the floor.
  862.  
  863. Items can't be immediately dropped to floor, because they might
  864. be on an entity that hasn't spawned yet.
  865. ============
  866. */
  867. void G_SpawnItem (gentity_t *ent, gitem_t *item) 
  868. {
  869.     // Weapons can be disabled
  870.     if ( item->giType == IT_WEAPON )
  871.     {
  872.         if ( !BG_IsWeaponAvailableForOutfitting ( item->giTag, 1 ) )
  873.         {
  874.             return;
  875.         }
  876.     }    
  877.  
  878.     G_SpawnFloat( "random", "0", &ent->random );
  879.     G_SpawnFloat( "wait", "0", &ent->wait );
  880.  
  881.     RegisterItem( item );
  882.     if ( G_ItemDisabled(item) )
  883.         return;
  884.  
  885.     ent->item = item;
  886.     // some movers spawn on the second frame, so delay item
  887.     // spawns until the third frame so they can ride trains
  888.     ent->nextthink = level.time + FRAMETIME * 2;
  889.     ent->think = FinishSpawningItem;
  890.  
  891.     ent->physicsBounce = 0.2f;        // items are bouncy
  892. }
  893.  
  894.  
  895. /*
  896. ================
  897. G_BounceItem
  898.  
  899. ================
  900. */
  901. void G_BounceItem( gentity_t *ent, trace_t *trace ) {
  902.     vec3_t    velocity;
  903.     float    dot;
  904.     int        hitTime;
  905.  
  906.     // reflect the velocity on the trace plane
  907.     hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
  908.     BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );
  909.     dot = DotProduct( velocity, trace->plane.normal );
  910.     VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );
  911.  
  912.     // cut the velocity to keep from bouncing forever
  913.     VectorScale( ent->s.pos.trDelta, ent->physicsBounce, ent->s.pos.trDelta );
  914.  
  915.     // check for stop
  916.     if ( trace->plane.normal[2] > 0 && ent->s.pos.trDelta[2] < 40 ) {
  917.         trace->endpos[2] += 1.0;    // make sure it is off ground
  918.         SnapVector( trace->endpos );
  919.         G_SetOrigin( ent, trace->endpos );
  920.         ent->s.groundEntityNum = trace->entityNum;
  921.         return;
  922.     }
  923.  
  924.     VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);
  925.     VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
  926.     ent->s.pos.trTime = level.time;
  927. }
  928.  
  929.  
  930. /*
  931. ================
  932. G_RunItem
  933. ================
  934. */
  935. void G_RunItem( gentity_t *ent ) 
  936. {
  937.     vec3_t        origin;
  938.     trace_t        tr;
  939.     int            contents;
  940.     int            mask;
  941.  
  942.     // if groundentity has been set to -1, it may have been pushed off an edge
  943.     if ( ent->s.groundEntityNum == -1 ) 
  944.     {
  945.         if ( ent->s.pos.trType != TR_GRAVITY ) 
  946.         {
  947.             ent->s.pos.trType = TR_GRAVITY;
  948.             ent->s.pos.trTime = level.time;
  949.         }
  950.     }
  951.  
  952.     if ( ent->s.pos.trType == TR_STATIONARY ) 
  953.     {
  954.         // check think function
  955.         G_RunThink( ent );
  956.         return;
  957.     }
  958.  
  959.     // get current position
  960.     BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
  961.  
  962.     // trace a line from the previous position to the current position
  963.     if ( ent->clipmask ) 
  964.     {
  965.         mask = ent->clipmask;
  966.     } 
  967.     else 
  968.     {
  969.         mask = MASK_PLAYERSOLID & ~CONTENTS_BODY;//MASK_SOLID;
  970.     }
  971.  
  972.     trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, ent->r.ownerNum, mask );
  973.  
  974.     VectorCopy( tr.endpos, ent->r.currentOrigin );
  975.  
  976.     if ( tr.startsolid ) 
  977.     {
  978.         tr.fraction = 0;
  979.     }
  980.  
  981.     // FIXME: avoid this for stationary?
  982.     trap_LinkEntity( ent );    
  983.  
  984.     // check think function
  985.     G_RunThink( ent );
  986.  
  987.     if ( tr.fraction == 1 ) 
  988.     {
  989.         return;
  990.     }
  991.  
  992.     // if it is in a nodrop volume, remove it
  993.     contents = trap_PointContents( ent->r.currentOrigin, -1 );
  994.     if ( contents & CONTENTS_NODROP ) 
  995.     {
  996.         // Gametype items are reported to the gametype when they are stuck like this
  997.         if ( ent->item && ent->item->giType == IT_GAMETYPE )
  998.         {
  999.             // Let the gametype handle the problem, if it doenst handle it and return 1 then 
  1000.             // just reset the gametype item
  1001.             if ( !trap_GT_SendEvent ( GTEV_ITEM_STUCK, level.time, level.gametypeItems[ent->item->giTag].id, 0, 0, 0, 0 ) )
  1002.             {
  1003.                 G_ResetGametypeItem ( ent->item );
  1004.             }
  1005.         }
  1006.  
  1007.         G_FreeEntity( ent );
  1008.         return;
  1009.     }
  1010.  
  1011.     G_BounceItem( ent, &tr );
  1012. }
  1013.  
  1014. gentity_t *CreateWeaponPickup(vec3_t pos,weapon_t weapon)
  1015. {
  1016.     gentity_t    *dropped;
  1017.     gitem_t        *item;
  1018.     
  1019.     if ( weapon < WP_KNIFE || weapon >= WP_NUM_WEAPONS )
  1020.     {
  1021.         return 0;
  1022.     }
  1023.  
  1024.     item = BG_FindWeaponItem (weapon);
  1025.     if(!item)
  1026.     {
  1027.         return(0);
  1028.     }
  1029.  
  1030.     dropped = G_Spawn();
  1031.     dropped->s.eType = ET_ITEM;
  1032.     dropped->s.modelindex = item - bg_itemlist;    // store item number in modelindex
  1033.     dropped->s.modelindex2 = 1;                    // This is non-zero is it's a dropped item
  1034.  
  1035.     dropped->classname = item->classname;
  1036.     dropped->item = item;
  1037.     VectorSet (dropped->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS);
  1038.     VectorSet (dropped->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS);
  1039.     dropped->r.contents = CONTENTS_TRIGGER;
  1040.  
  1041.     dropped->touch = Touch_Item;
  1042.  
  1043.     G_SetOrigin( dropped, pos );
  1044.     dropped->s.pos.trType = TR_GRAVITY;
  1045.     dropped->s.pos.trTime = level.time;
  1046.     VectorSet( dropped->s.pos.trDelta,0.0,0.0,0.0);
  1047.  
  1048.     dropped->s.eFlags |= EF_BOUNCE_HALF;
  1049.     dropped->flags = FL_DROPPED_ITEM;
  1050.  
  1051.     trap_LinkEntity (dropped);
  1052.  
  1053.     return dropped;
  1054. }
  1055.